//
// Created by fairy on 2025/5/11.
//
/*
 * 修复并优化后的多路复用输入示例程序
 * 主要改动：修复文件打开错误、poll超时设置、循环逻辑错误及缓冲区溢出等问题
 */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <poll.h>

#define MAX_BUFFER_SIZE 1024     // 缓冲区大小（包含结尾的空字符）
#define IN_FILES 3               // 监控的文件描述符数量（标准输入+两个文件）
#define TIME_DELAY 60000         // poll超时时间（60秒）
#define MAX(a, b) ((a > b)?(a):(b))

int main(void)
{
    struct pollfd fds[IN_FILES]; // pollfd结构数组
    char buf[MAX_BUFFER_SIZE + 1]; // 缓冲区（+1用于存放结尾的空字符）
    int i, res, real_read;

    /************** 初始化文件描述符 **************/
    // 标准输入（文件描述符0）
    fds[0].fd = STDIN_FILENO;

    // 打开第一个输入文件（注意修正文件名拼写错误）
    if ((fds[1].fd = open("in1", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("Open in1 error"); // 使用perror显示具体错误
        return 1;
    }

    // 打开第二个输入文件
    if ((fds[2].fd = open("in2", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("Open in2 error");
        return 1;
    }

    // 初始化所有文件描述符的监听事件为POLLIN（普通数据可读）
    for (i = 0; i < IN_FILES; i++) {
        fds[i].events = POLLIN;
    }

    /************** 主事件循环 **************/
    while (1) {
        // 使用poll等待事件发生，设置60秒超时
        res = poll(fds, IN_FILES, TIME_DELAY);

        if (res < 0) {
            perror("Poll error");
            return 1;
        } else if (res == 0) {
            printf("Poll timeout reached.\n");
            continue; // 超时后继续监听
        }

        // 检查所有文件描述符的事件
        for (i = 0; i < IN_FILES; i++) {
            // 先检查错误事件（挂起或错误）
            if (fds[i].revents & (POLLERR | POLLHUP)) {
                fprintf(stderr, "Error occurred on fd%d\n", i);
                close(fds[i].fd);
                fds[i].events = 0; // 取消监听
                continue;
            }

            // 检查数据可读事件
            if (fds[i].revents & POLLIN) {
                memset(buf, 0, sizeof(buf)); // 清空缓冲区

                // 执行非阻塞读取
                real_read = read(fds[i].fd, buf, MAX_BUFFER_SIZE);

                if (real_read < 0) {
                    // 处理非预期错误（除了EAGAIN/EWOULDBLOCK）
                    if (errno != EAGAIN) {
                        perror("Read error");
                        return 1;
                    }
                } else if (real_read == 0) {
                    // 文件到达结尾（EOF）
                    printf("File fd%d closed\n", i);
                    close(fds[i].fd);
                    fds[i].events = 0; // 取消监听
                } else {
                    // 成功读取数据
                    buf[real_read] = '\0'; // 确保字符串终止

                    if (i == 0) { // 标准输入处理
                        // 检测退出指令（q/Q+换行符）
                        if (buf[0] == 'q' || buf[0] == 'Q') {
                            printf("Exit command received.\n");
                            goto exit_loop;
                        }
                    } else { // 文件输入处理
                        printf("From fd%d: %s", i, buf);
                    }
                }
            }
        }

        // 检查是否所有文件描述符都已关闭
        if (!fds[0].events && !fds[1].events && !fds[2].events) {
            printf("All input sources closed.\n");
            break;
        }
    }

exit_loop:
    /************** 清理资源 **************/
    // 显式关闭所有打开的文件描述符
    for (i = 0; i < IN_FILES; i++) {
        if (fds[i].fd >= 0) close(fds[i].fd);
    }

    return 0;
}